<template>
  <!-- table -->
  <el-table
    border
    stripe
    style="width:100%"
    fit
    highlight-current-row
    :data="data"
    v-if="data != undefined && data.length > 0"
  >
    <!-- 文件类型 -->
    <el-table-column
      width="120px"
      label="文件类型"
      prop="fileType"
      align="center"
    >
    </el-table-column>
    <!-- 资源描述 -->
    <el-table-column
      width="auto"
      label="文件描述"
      prop="discription"
      align="center"
    >
    </el-table-column>
    <!-- 文件列表 -->
    <el-table-column width="100px" label="文件列表" align="center">
      <template v-slot="scope">
        <el-button
          type="text"
          class="el-button-projectresource"
          size="mini"
          @click="showResources(scope.row, scope.$index)"
          >查看</el-button
        >
      </template>
    </el-table-column>
    <!-- 操作 -->
    <el-table-column width="100px" label="操作" align="center">
      <template v-slot="scope">
        <el-button
          type="text"
          size="mini"
          class="el-button-projectresource"
          @click="uploadResources(scope.row, scope.$index)"
          >上传</el-button
        >
      </template>
    </el-table-column>
  </el-table>
  <!-- upload dialog -->
  <el-dialog
    v-model="isShowUploadResourceDialog"
    center
    width="40%"
    :close-on-click-modal="false"
    title="上传附件"
  >
    <el-upload
      action=""
      multiple
      :auto-upload="false"
      :on-change="(file, fileList) => handleFileChange(file, fileList)"
      :on-remove="(file, fileList) => handleFileRemove(file, fileList)"
      :file-list="resourcesToBeUpload"
      :show-file-list="false"
    >
      <template #trigger>
        <el-button size="small" type="primary" style="margin-bottom:20px"
          >选取文件</el-button
        >
      </template>
      <el-button
        size="small"
        type="success"
        @click="uploadFile(nowFileType)"
        style="margin-left: 100px"
        >上传到服务器</el-button
      >
      <template #tip>
        <div class="el-upload__tip">
          文件大小不超过1GB
        </div>
      </template>
      <!-- show files -->
      <el-table
        border
        stripe
        style="width:100%"
        fit
        highlight-current-row
        :data="resourcesToBeUpload"
        v-if="resourcesToBeUpload.length > 0"
      >
        <!-- 添加索引 -->
        <el-table-column type="index" width="50px" label="序号" align="center">
        </el-table-column>
        <!-- 文件名 -->
        <el-table-column
          width="200px"
          label="文件名"
          prop="name"
          align="center"
        ></el-table-column>
        <el-table-column
          label="文件大小"
          prop="size"
          width="100px"
          align="center"
        >
          <template v-slot="scope">
            <span>{{ formatFileSize(scope.row.size) }}</span>
          </template>
        </el-table-column>
        <el-table-column label="上传进度" align="center">
          <template v-slot="scope">
            <el-progress
              :stroke-width="10"
              :percentage="scope.row.percentage"
              :status="scope.row.percentage >= 100 ? 'success' : undefined"
            ></el-progress>
          </template>
        </el-table-column>
      </el-table>
    </el-upload>
    <!-- large file -->
  </el-dialog>
  <!-- resource list dialog -->
  <el-dialog v-model="isShowResourceListDialog" width="70%" title="查看文件">
    <MyTable
      :tableTitle="`附件`"
      tableID="resource-list-table"
      :tableCols="resourceListPattern"
      :tableData="nowResources"
      :isReadonly="false"
      :tableRowDelete="deleteResource"
      :tableRowEdit="previewResource"
      :tableRowAdd="uploadResourcesAnother"
    />
  </el-dialog>
  <!-- use when show a excel -->
  <el-dialog v-model="isShowPreviewDialog" width="70%" title="文件预览" center>
    <el-table
      :data="nowExcelTableData"
      border
      stripe
      style="width:100%"
      fit
      highlight-current-row
      v-if="/.sheet$/.test(fileExtensionType)"
    >
      <el-table-column
        v-for="(item, index) in nowExcelTableCols"
        :key="index"
        :prop="item"
        :label="item"
        width="auto"
      >
        <template v-slot="scope">
          <span>{{ scope.row[item] }}</span>
        </template>
      </el-table-column>
    </el-table>
  </el-dialog>
</template>

<script lang="ts">
import MyTable from "@/components/MyTable";
import {
  addFileToProject,
  deleteProjectResource,
  queryProjectResource,
  queryProjectResourceByType,
  queryProjectResourceList
} from "@/api/projectResourceApi";
import { ProjectResource, Resource } from "@/interface/entity";
import store from "@/store";
import { computed, defineComponent, ref } from "vue";
import { constObjs, validatePattern } from "@/const/const";
import XLSX from "yxg-xlsx-style";
import { Guid } from "guid-typescript";
import { ElMessage, ElMessageBox } from "element-plus";

export default defineComponent({
  name: "ProjectResource",
  components: {
    MyTable
  },
  setup() {
    // dialog
    const isShowUploadResourceDialog = ref<boolean>(false);
    const isShowResourceListDialog = ref<boolean>(false);
    const isShowPreviewDialog = ref<boolean>(false);
    // e.g 物资准备
    const nowFileType = ref<string>("");
    // 文件扩展名 e.g xlsx
    const fileExtensionType = ref<string>("");
    // when uploading resource
    const resourcesToBeUpload = ref<object[]>([]);
    // when showing resources
    const nowResources = ref<Resource[]>([]);
    // when previewing a resource
    const nowResourceUrl = ref<string>("");
    // column when previewing excel
    const nowExcelTableCols = ref<string[]>([]);
    // data to preview excel when previewing;
    const nowExcelTableData = ref<object[]>([]);
    // when showing
    const showResources = async (row: object, index: number) => {
      const projectResource = row as ProjectResource;
      const projectGuid = store.state.projectResources.projectGuid;
      // query by type
      await queryProjectResourceByType(projectGuid, projectResource.fileType);
      // resources
      nowResources.value = store.state.projectResources.resources.find(
        resource => resource.fileType == projectResource.fileType
      )?.resource as Resource[];

      // nowResources.value = projectResource.resource;
      nowFileType.value = projectResource.fileType;
      isShowResourceListDialog.value = true;
    };
    const uploadResources = (row: object, index: number) => {
      // init
      resourcesToBeUpload.value = [];

      nowFileType.value = (row as ProjectResource).fileType;
      isShowUploadResourceDialog.value = true;
    };
    // when uploading, row is ProjectResource ()
    const uploadResourcesAnother = () => {
      // init
      resourcesToBeUpload.value = [];
      isShowUploadResourceDialog.value = true;
    };

    // delete A resource, row is a resource object
    const deleteResource = async (rows: Resource[]) => {
      if (store.state.nowUserPermissionList.includes("projectResource")) {
        const projectGuid = store.state.projectResources.projectGuid;
        let rowIndex = 0;
        // delete in db
        await Promise.all(
          rows.map(async row => {
            nowResources.value.forEach((value, index) => {
              if (value.url == row.url) rowIndex = index;
            });
            nowResources.value.splice(rowIndex, 1);
            await // delete loacl resource
            deleteProjectResource(
              projectGuid,
              nowFileType.value,
              (row as Resource).name
            );
          })
        ).then(() => {
          ElMessage.success("批量删除成功");
        });

        await queryProjectResourceList(projectGuid);
      } else {
        ElMessage.error(
          `您当前的账户:[${store.state.username}]无权限删除项目附件，请联系管理员管理该账户权限`
        );
      }
    };

    const previewResource = async (row: object) => {
      const resource = row as Resource;
      const projectGuid = store.state.projectResources.projectGuid;
      // fileExtensionType
      fileExtensionType.value = resource.url.type.toLowerCase();

      console.log(fileExtensionType.value);

      nowResourceUrl.value = URL.createObjectURL(resource.url);
      // todo if not picture and video and audio
      // choose different way to preview base on the type
      if (validatePattern.wordAndppt.test(fileExtensionType.value)) {
        // generate pdf
        await queryProjectResource(
          store.state.projectResources.projectGuid,
          nowFileType.value,
          resource.name,
          true,
          resource
        );

        // now filename
        const nowFileName = resource.name.split(".")[0] + ".pdf";
        //(the resource.url is changed after queryProjectResource())
        const url = URL.createObjectURL(resource.url);
        //  preview generated pdf
        window.open(url, "_blank");
        // todo delete after preview is finished
        await deleteProjectResource(
          projectGuid,
          nowFileType.value,
          nowFileName
        );
      } else if (
        validatePattern.pdfAndVideoAndImage.test(fileExtensionType.value)
      ) {
        window.open(nowResourceUrl.value, "_blank");
      } else if (validatePattern.excel.test(fileExtensionType.value)) {
        // init
        nowExcelTableData.value = [];
        nowExcelTableCols.value = [];
        // load blob
        const fileReader = new FileReader();
        fileReader.onload = ev => {
          try {
            if (ev.target != null) {
              const data = ev.target.result;
              const workbook = XLSX.read(data, {
                type: "binary"
              });
              // first sheet
              const wsname1 = workbook.SheetNames[0];
              // json object
              const ws1 = XLSX.utils.sheet_to_json(
                workbook.Sheets[wsname1]
              ) as object[];
              // generate excel col
              Object.keys(ws1[0]).forEach(key => {
                nowExcelTableCols.value.push(key);
              });
              // preview in el-table
              nowExcelTableData.value = ws1;
              isShowPreviewDialog.value = true;
            }
          } catch (e) {
            console.log(e);
            return;
          }
        };
        fileReader.readAsBinaryString(resource.url);
      } else {
        ElMessage.error("当前文件格式暂时不支持预览！");
      }
    };

    const handleFileChange = (file: object, fileList: object[]) => {
      // 只有文件改变的时候才继续下面的操作
      if (file["status" as keyof object] !== "ready") {
        return;
      }
      const existFile = fileList
        .slice(0, fileList.length - 1)
        .find(f => f["name" as keyof object] === file["name" as keyof object]);
      if (existFile) {
        ElMessage.error("文件已存在！");
        fileList.pop();
      }
      resourcesToBeUpload.value = fileList;
    };

    const handleFileRemove = (file: object, fileList: object[]) => {
      resourcesToBeUpload.value = fileList;
    };

    // 上传
    const uploadFile = async (prop: string) => {
      // e.g project.resource1
      const projectGuid = store.state.projectResources.projectGuid;

      // 循环里面遍历文件，对每个文件分片异步请求。异步循环结束以后更新数据
      await Promise.all(
        resourcesToBeUpload.value.map(async res => {
          const tmpGuid = Guid.create().toString();
          // 分片上传
          await addFileToProject(projectGuid, res, prop, 0, tmpGuid);
        })
      );
      // 。异步循环结束以后更新数据。后面点击查看会自动查询更新以后的数据
      await queryProjectResourceByType(projectGuid, prop);

      // 更新文件列表
      nowResources.value = store.state.projectResources.resources.find(
        resource => resource.fileType == prop
      )?.resource as Resource[];

      // 上传完成提示
      ElMessageBox.confirm("上传完毕, 是否继续上传?", "提示", {
        confirmButtonText: "继续上传",
        cancelButtonText: "取消上传",
        type: "info"
      }).catch(() => {
        isShowUploadResourceDialog.value = false;
      });
    };

    const formatFileSize = (size: number): string => {
      if (size < 0) {
        return "invalid size!";
      }
      // 1024^x = y
      const pow = Math.floor(Math.log(size) / Math.log(1024));
      switch (pow) {
        case 0:
          return size.toFixed(2) + "B";
        case 1:
          return (size / 1024).toFixed(2) + "KB";
        case 2:
          return (size / Math.pow(1024, 2)).toFixed(2) + "MB";
        default:
          return (size / Math.pow(1024, 3)).toFixed(2) + "GB";
      }
    };

    const formatProgress = (percentage: number) => {
      return percentage === 100 ? "完成" : `${percentage} + %`;
    };

    return {
      validatePattern,
      isShowUploadResourceDialog,
      isShowResourceListDialog,
      isShowPreviewDialog,
      nowFileType,
      fileExtensionType,
      resourcesToBeUpload,
      nowResources,
      nowResourceUrl,
      nowExcelTableCols,
      nowExcelTableData,
      data: computed(() => store.state.projectResources.resources),
      resourceListPattern: computed(() => constObjs.resourceListPattern),
      deleteResource,
      previewResource,
      handleFileChange,
      handleFileRemove,
      uploadFile,
      showResources,
      uploadResources,
      uploadResourcesAnother,
      formatFileSize,
      formatProgress
    };
  }
});
</script>

<style scoped></style>
